jsxgraph.js是javascript的一個動態幾何函式庫,因此操作JSXGraph之前,必須對javascript這個程式語言有基本的了解。如果您已經非常熟悉javascript,可以跳過今天的內容,直接閱讀下一篇。既然是偷吃步,就難免丟三落四,也沒有一個系統性,只是把我常用的語法簡單寫上而已,不要期待太高。可以按下F12
,然後按下console的標籤,即可執行javascript的語法。
沒有學過javascritp的朋友們,在瀏覽器(Chrome或edge)瀏覽任何頁面時,按下
F12
即可進入開發者模式,在Console標籤下直接輸入程式,可以觀察到javascript執行的結果;console.log是在初學和偵錯時最常用的函數指令。
Javascript是一個專門作為網頁開發的程式語言,主要執行的環境是網頁瀏覽器(像chrome、firefox、edge…等),後來由於Node.js的成熟,讓它也可以在其它環境中執行。Javascript起初只是一個簡單腳本語言(script),由於網路的開速發展,在歷史的因果下,成為一種既簡單又複雜的語言。由於JSXGraph主要是在瀏覽器在執行的函式庫,各個函式包裝完整,近乎近似於Geogebra這款套裝軟體,只需簡單操作javascript。因此除了基本的變數宣告、資料型態、控制語法與函式概念,主要探討如何操作DOM(Document Object Model)的操作。
如果要完整說明javascript,可以完整的寫完一本書(市面上已經有很多相關書籍,網路資源也為數不少),所以關於javascript細節部分,我們將故意略過不談,有興趣的朋友可以參考mdn web doc相關的說明或網路其它資源。
由於發展歷史的緣故,javascript原本是很鬆散的弱型態程式語言,變數甚至不用宣告也可以使用,目前則提供了var、let和const三種宣告方式。如果變數沒有宣告,這個變數會成為全域變數,以瀏覽器而言便是window。如果用var宣告,變數的作用範圍便是所在的宣告變數的函式範圍內,目前JSXgraph官網內的範例,大部分都是使用var宣告。ES6之後,javascript提供了let和const兩個變數宣告的方法,可以讓變數的作用範圍侷限在區塊內(即{}之間),目前主流的程式撰寫習慣都是用let和const宣告,而經由const宣告後的變數,不可以更改其值。
javascript的變數命名規則如下:第一個字母必須是錢字符$
、底線_
和英文字母,由於有些人使用Latex語法時,習慣用錢字符當識別字,而首字母使用底線符號則是為許多程式設計人員作為類別的私有變數命名習慣,因此建議用英文字母作為變數首字母。第二個字母之後則可以使用錢字符$
、底線_
、英文字母和數字命名。
變數命名時,盡量使用完整英文字意命名,以增加程式的可讀性。撰寫javascript時,我個人習慣使用小駝峰式命名法(Camel Case,第一個單字第一個字母為小寫,之後每一個單字的開頭為大寫,不包含空格,例:firstPoint)。變數命名非常重要,命名完成通常也代表程式的架構也有了初步的進展。
Javascript是一種動態型別的語言,不用宣告變數的型別,它會根據我們給予變數的值來判定資料的型別。我們常用到基本資料型態包含字串(string)、數字(number)、布林值(boolean),複合資料型態則有陣列(array)和物件(Object)。
'字串'
或雙引號"字串"
包覆,兩者不可混合使用,另外ES6之後提供模板字符串,使用``(和~符號同一個鍵)包夾,模板字符串內可以下列形式嵌入變數和運算式:`${ 變數 }`,更具靈活與彈性。true
(真)和false
(假)兩種可能值。[]
包覆我們的資料,資料間用逗點,
分隔,陣列中的資料可以是任何的資料型態,也未必要相同,但是使用習慣上,建議陣列儲存相同資料型態的資料。例如const a = ['lemon', 'banana', 'pipeapple']
,javascript內建許多陣列方法(method),我們會在適當的時機介紹。{}
包覆我們的資料,資料間用逗點,
分隔,物件的值也可以是任何資料型態,物件內也可以再包含物件,存取物件屬性時使用.
。例如const people = {name: 'John', age: 28, isActive: true}
,則people.name的值為'John',people.age的值為28,people.isActive的值為true。在JSXGraph中,我們通常使用幾何物件進行屬性的設定。=
(指定),例如x = y
就是y
儲存的值指定給x
。+
(加)、-
(減)、*
(乘)、/
(除)、%
(餘)、**
(次方);指定運算字可以搭配算術運算子,例如:x += y
和x = x + y
都是把x + y
計算的結果指定給x
。>
(大於)、>
=(大於或等於)、<
(小於)、<=
(小於或等於)、===
(等於)、!==
(不等於),注意,這邊等於的比較使用三個等號,不等於使用二個等號,理由並不贅述:比較運算子的結果會傳回布林值true
或false
。&&
代表AND運算,||
代表OR運算,~
代表NOT運算。條件 ? 值1 : 值2
條件若為「真」則得到值1,若為「否」則得到值2。+
也可以用作字串連接,例如:'abc' + 'def'
得到字串'abcdef
。解構賦值 (Destructuring assignment)語法...
是一種 JavaScript 運算式,可以把陣列或物件中的資料解開擷取成為獨立變數。我們可以把陣列想像成一個裏面有一格一格的盒子,解構就是把盒子打開,把盒子內每一格裝的東西把它拿出來,在JSXGraph新增或覆蓋屬性設定時非常方便。
let a = [1, 2, 3, 4, 5];
let b = [...a, 6, 7];
console.log(b); //顯示 [1, 2, 3, 4, 5, 6, 7]
let Orthocentre = {color: '#33333', size: 3, withLabe: true};
Orthocetre = {...Orthocetre, label: {color: 'blue'}};
console.log(Orthocetre); //顯示 {color: '#33333', size: 3, withLabe: true, {color: 'blue'}}
一般函式建構語法
function 函數名(參數1,參數2,...) {
// 函式敘述
// return 傳回值
}
函式可以不傳回任何值,也就是省略return那一行。
function add(a, b) {
return a + b
}
函數表表示
Javascript的函式是一級物件(first-class object),也就是說,函式可以是別的函式的參數,傳回值,也可以是一個變數的值。
const myAdd = function add(a, b) {
return a + b
}
let c = myAdd(1, 3)
匿名函式
使用函數表達式時,可以不給予函數名,即成為匿名函數
const myAdd = function(a, b) {
return a + b
}
let c = myAdd(1, 3)
匿名函數在將函式當作一個參數傳給其它函式時使用,非常方便,這種函式也稱為回呼函式(callback function)。
function functionValue(x, f) {
return f(x)
}
const square = function(t) {
return t * t
}
let c = functionValue(6, square)
console.log(c) // 輸出結果為36
箭頭函式
箭頭函式(arrow function)是匿名函式的一種省略語法,其寫法如下:
(參數1, 參數2, …) => {
// 函式敘述
// return 傳回值
}
只有一個參數時,括號()
也可以省略,如果函式敘述只有傳回值一行,return
關鍵字和大括號{}
也可以省略。箭頭函式常使用在回呼函式中,在上面的程式中,我們可以改寫成
let c = functionValue(6, t => t * t)
這樣寫等同於
let c = functionValue(6, function(t){ return t * t) }
遞迴函式
遞迴函式和數學上的遞迴關係非常相近,例如:用輾轉相除法求兩整數的最大公因數即是遞迴關係,我們可以這樣敘述輾轉相除法:「假設兩整數a>b,且a除以b的餘數為r,則a和b的最大公因數等於b和r的最大公因數。」,把它寫成程式只有短短的幾行。
//假設 a > b
function gcd(a, b) {
let r = a % b
if (r === 0) {
return b
} else {
return gcd(b, r)
}
}
console.log(gcd(1071, 462)) //結果為21
數學上很多原理都是遞迴關係式,也就可以用遞迴函式輕鬆寫出程式。例如:綜合除法、巴斯卡三角形計算組合數、錯排、快速傅立葉轉換(FFT)…,凡是能寫出遞迴關係式的演算法,通常都是快速的演算法。我寫過一個 錯排的程式,就在這邊分享,算是今天較枯躁內容的一個彩蛋。
錯排的程式是把測試字串'abcde'所有a不在第1個位置,且b不在第2個位置,且c不在第3個位置,且d不在第4個位置,且e不在第5個位置的字串找出來。假設n個字串的錯排數是P(n),則 P(1)=0,P(2)=1,P(n)=n*[P(n-1)+P(n-2)]
流程控制對數學老師說只是小菜一碟,if...else...語法顯而易見,就不提供程式範例了;迴圈則對陣列和物件的操作很方便
if else
// 語法一
if (條件) {
// 敘述
}
如果條件為真則執行大括號內敘述,如果為否則跳過大括號內敘述。
// 語法二
if (條件) {
// 敘述一
} else {
// 敘述二
}
如果條件為真則執行敘述一,如果為否則執行敘述二。
for
for 迴圈用來重覆執行 for 區塊內的敘述。
// 語法一
for (let 變數起始值; 執行條件; 變數運算式) {
// 敘述
}
首先檢查變數起始是否滿足執行條件,如果滿足,則執行迴圈內敘述;接著執行變數的運算式,執行後再檢查是否滿足執行條件,如果滿足,則再執行迴圈內敘述,一直重覆這個流程,直到變數不滿足執行條件其流程圖如下:
// 語法二
for (let 值 of 陣列) {
// 敘述
}
let...of語法可在陣列中使用
// 語法三
for (let 鍵 in 物件) {
// 敘述
}
const a = [1, 1, 2, 3, 5, 8]
for (let x of a) {
console.log(x)
}
若想要遍歷物件,可用let...in語法比較方便。
const pointA = {
color: 'red',
size: 3,
face: 'cross'
}
for (let key in pointA) {
console.log(key, pointA[key])
}
break和continue
break指令會跳出整個 for 迴圈,讓程式往下執行;continue指令則會跳出本次迴圈,執行下一個變數運算式的迴圈。
心裏一直很猶豫要不要寫今天的內容,但是想想,應該有人對javascript這個語言沒有任何基礎,還是決定寫了。一旦要寫,內容的取捨又很糾結。寫得太多,發現會寫不完;寫得太少,又覺得無法發揮現代javascript的特特色,於是形成了選擇障礙。Javascript的內容非三言二語能交待清楚,為了快速進入JSXGraph函式庫的使用,最後整理出未來內容可能用到的語法,為求精簡,難免顧此失彼,還敬請見諒。還好很多的邏輯觀念和運算順序是數學老師們習以為常的知識,所以沒有給很多的範例,若有疑問,煩請可以直接在下方留言,建議一開始寫程式的時候,先以自己有把握的指令為主,因為完成程式有很多的方式,先讓程式能跑,慢慢再求指令的簡潔。今日的發文就在此告一段落,感謝閱讀與分享。